#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>   // for tprintf
#include <stdarg.h> // for tprintf
#include <getopt.h>
#include "safecalls.h"
#include "networkinglib.h"

/*
 * split - extracts words in <str> delimited by <delim> and populates <words>
 *
 * Parameters:
 *    str - the string containing words to extract
 *    delim - the delimiter character
 *    words - the array to be populated with the words extracted from <str>
 *    maxwords - the maximum number of words to extract from <str>
 *    ignoreEmpty - if TRUE, ignores empty words (if space is the delimiter, this should probably be TRUE)
 */
int split(char *str, char delim, char *words[], int maxwords, int ignoreEmpty)
{
    int numwords = 0;
    char *delimLoc;

    while ((delimLoc = strchr(str, delim)) != NULL && numwords < maxwords) {
        if ((delimLoc != str) || ignoreEmpty) {
            words[numwords] = str;
            numwords++;
            *delimLoc = 0;
        }
        str = delimLoc + 1;
    }
    if (strlen(str) > 0 && numwords < maxwords) {
        words[numwords] = str;
        numwords++;
    }
    return numwords;
}

// Use this like printf. This prints a timestamp and the process pid before the 
// string you provide
int tprintf(const char *fmt, ...) {
  va_list args;
  struct tm *tstruct;
  time_t tsec;

  tsec = time(NULL);
  tstruct = localtime(&tsec);

  printf("%02d:%02d:%02d %5d| ",
         tstruct->tm_hour,
         tstruct->tm_min,
         tstruct->tm_sec,
         getpid());

  va_start(args, fmt);
  return vprintf(fmt, args);
}


int shutdownflag = 0;

void handleshutdown(int sig)
{
    tprintf("CTRL-C detected...\n");
    shutdownflag = 1;
}

void sendresponse(int sock, char *path)
{
    char buf[250];
    FILE *infile;
    int bytesRead;

//     sprintf(buf, "HTTP/1.0 200 OK\nContent-type: text/html\n\n");
//     write_buffer(sock, buf, strlen(buf));
  //  printf("Sock is: %i\n", sock);
    
    infile = fopen(path,"r");
    if (!infile)
    {
      sprintf(buf, "HTTP/1.0 404 Not Found\n\n");
      write_buffer(sock, buf, strlen(buf));
      printf("File not found...\n");
    }
    else
    {
      sprintf(buf, "HTTP/1.0 200 OK\nContent-type: text/html\n\n");
      write_buffer(sock, buf, strlen(buf));
      while ((bytesRead = fread(buf, 1, sizeof(buf), infile)) > 0) 
      {
	write_buffer(sock, buf, bytesRead);
      }
    fclose(infile);
    }
  

}


#define USAGE_STRING "Usage: webserver -p <port> -r <document root directory>\n"

char *port;
char directory[1024];

// Process command line arguments. Uses GNU getopt() function.
void processargs(int argc, char **argv) {
  int next_option;
  do {
    next_option = getopt(argc, argv, "p:o:");
    if (next_option != -1) {
      switch (next_option)
      {
        case 'p': /* -p -- port option  */
          port = optarg;
          break;
	case 'r': /* -r -- document root directory */
	  strlcpy(directory, optarg, sizeof(directory));
	  break;
        default:
          /* Unknown option detected. Print it to standard
                output, and exit with exit code zero (normal termination). */
          fprintf(stderr, USAGE_STRING);
          exit(0);
  
      }
    }
  } while (next_option != -1);
  
  if (port == NULL) {
          fprintf(stderr, USAGE_STRING);
          exit(1);
  }
	  
  if (!*directory)
  {
    getcwd(directory, sizeof(directory));
  }
  
}

int main(int argc, char **argv) {
  int mastersock, workersock;
  struct sockaddr_in socketaddr;
  int addrlen, numBytes, numwords;
  char buffer[1024];
  char size[100];
  char *words[3];

  
  processargs(argc, argv);
  
  // set up ctrl-c handler
  struct sigaction sa;
  memset (&sa, 0, sizeof(sa));  // clear structure
  sa.sa_handler = handleshutdown;
  sigaction(SIGINT, &sa, NULL);

  // open the main socket
  mastersock = serverinit(port, "tcp");

  tprintf("The server is active on port %s.  You may terminate it with Ctrl-C.\n", port);

  while (!shutdownflag) {
    addrlen = sizeof(socketaddr);

    workersock = accept(mastersock, (struct sockaddr *) &socketaddr, &addrlen);
    if (workersock < 0) {
      if (shutdownflag) {
        // interrupted by a CTRL-C
        continue;
      }
      HandleError(errno, "accept", "couldn't open worker socket");
    }

    tprintf("Received connection from a client at %s port %d\n", inet_ntoa(socketaddr.sin_addr),
             ntohs(socketaddr.sin_port));
    fflush(stdout);

    if ((numBytes = readnlstring(workersock, buffer, sizeof(buffer))) > 0) 
    {
        // parse HTTP response
        //printf("buffer: %s\n", buffer);
        if ((numwords = split(buffer, ' ', words, 3, 1)) == 3) 
	{
          //Account for other valid HTTP requests that are not accepted in this program
	  if (strcmp(words[0], "GET"))
	  {
	    //bad request
	    printf("Bad request\n");
	    char buf[250];
	    sprintf(buf, "\nHTTP/1.0 400 Bad Request: workersock closed.\n\n");
	    write_buffer(workersock, buf, strlen(buf));
	    safeclose(workersock);
	    
	  }
	  else
	  //If we didn't already close the workersock, continue with processing of the path
	  {
	    printf("Processing http request...\n");
	    char path[100];
	    //char *patharg = words[1];
	    //char pathchar = patharg[0];
	    if (words[1][0]=='/')
	    {
	      snprintf(path, sizeof(path), "%s%s", directory, words[1]);
	    }
	    else
	    {
	      printf("Invalid directory structure \\\\do something here...");
	      
	    }
	    tprintf("Client requested %s...\n", path);
	    fflush(stdout);
	    /* read rest of request header lines */
	    while (readnlstring(workersock, buffer, sizeof(buffer)) > 0 && buffer[0] != '\r' && buffer[0] != '\n')
	      /* throw it away */ ;


	    sendresponse(workersock, path);
	  }
        }

    }
    else if (1==0)
    {
      //return error if too big
      char buf[250];
      sprintf(buf, "\nHTTP/1.0 400 Bad Request\n\n");
      write_buffer(workersock, buf, strlen(buf));
    }

    if (workersock)
    {
      safeclose(workersock);
    }

  }

  tprintf("Shutting down.\n");

  safeclose(mastersock);

  return 0;
}
